package main.core.xml;

import main.core.Item;
import main.core.Settings;
import main.core.utils.Useful;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class XMLItemsLoader {
	
	public static ArrayList<Item> loadFile(File file, int type) throws Exception
	{
		ArrayList<Item> items = new ArrayList<Item>();
		try {
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder dBuilder;
			dBuilder = dbFactory.newDocumentBuilder();
			Document doc = dBuilder.parse(file);
			Element root_element = doc.getDocumentElement();
			root_element.normalize();
			if(!checkRoot(root_element))
				throw new Exception("Root isn't correct");
			items = parseRoot(root_element, type);
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return items;
	}
	
	private static ArrayList<Item> parseRoot(Element root, int type)
	{
		ArrayList<Item> its = null;
		Node node = root.getFirstChild();
		if(type == XMLItems.SETTINGS_TYPE)
		{
			while(node.getNodeType() != Node.ELEMENT_NODE)
				node = node.getNextSibling();
			Element set_el = (Element)node;
			if(set_el.getTagName().equals(XMLItems.SETTINGS))
				parseSettings(set_el);
		} else if(type == XMLItems.ITEMS_TYPE)
		{
			while(node.getNodeType() != Node.ELEMENT_NODE)
				node = node.getNextSibling();
			Element it_el = (Element)node;
			System.out.println(it_el.getTagName());
			if(it_el.getTagName().equals(XMLItems.ITEMS))
				its = parseItems(it_el);
		}
		return its;
	}
	
	private static ArrayList<Item> parseItems(Element items)
	{
		NodeList item_list = items.getChildNodes();
		ArrayList<Item> its = new ArrayList<Item>();
		for(int i = 0; i < item_list.getLength(); ++i)
		{
			Node cur_node = item_list.item(i);
			if(cur_node.getNodeType() == Node.ELEMENT_NODE)
			{
				Element item = (Element)cur_node;
				if(item.getTagName().equals(XMLItems.ITEM))
					its.add(parseItemProperties(item));
			}
		}
		return its;
	}
	
	private static Item parseItemProperties(Element it_el)
	{
		Item item = new Item();
		NodeList prop_list = it_el.getChildNodes();
		for(int i = 0; i < prop_list.getLength(); ++i)
		{
			Node cur_node = prop_list.item(i);
			if(cur_node.getNodeType() == Node.ELEMENT_NODE)
			{
				Element prop = (Element)cur_node;
				setItemProperty(item, prop.getTagName(), prop.getTextContent());
			}
		}
		return item;
	}
	
	private static void setItemProperty(Item item, String property, String value)
	{
		try {
			Class<?> cls = Item.class;
			Class<?> partypes[] = new Class[1];
			partypes[0] = String.class;
			Method meth = cls.getMethod(Useful.getSetter(property), partypes);
			Object arglist[] = new Object[1];
			arglist[0] = value;
			meth.invoke(item, arglist);
		}
		catch (Throwable e) {
			System.err.println(e);
		}
	}
	
	private static boolean checkRoot(Element element)
	{
		return element.getTagName().equals(XMLItems.BPE);
	}
	
	private static void parseSettings(Element settings)
	{
		NodeList childs = settings.getChildNodes();
		for(int i = 0; i < childs.getLength(); ++i)
		{
			Node cur_node = childs.item(i);
			if(cur_node.getNodeType() == Node.ELEMENT_NODE)
			{
				Element cur_el = (Element)cur_node;
				setSettingsProperty(cur_el.getTagName(), cur_el.getTextContent());
			}
		}
	}
	
	private static void setSettingsProperty(String property, String value)
	{
		try {
			Class<?> cls = Settings.class;
			Class<?> partypes[] = new Class[1];
			partypes[0] = String.class;
			Method meth = cls.getMethod(Useful.getSetter(property), partypes);
			Settings set = Settings.getInstance();
			Object arglist[] = new Object[1];
			arglist[0] = value;
			meth.invoke(set, arglist);
		}
		catch (Throwable e) {
			System.err.println(e);
		}
	}
}
